Here is a complete NgRx cheatsheet that covers everything you need to know about NgRx. You can use this cheatsheet as a quick reference guide for NgRx development.
NgRx Basics
Install NgRx
npm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/router-store
Setup NgRx Store
import { StoreModule } from '@ngrx/store';
import { reducers } from './reducers';
@NgModule({
imports: [
StoreModule.forRoot(reducers)
]
})
export class AppModule { }
Create Action
import { createAction, props } from '@ngrx/store';
export const increment = createAction('[Counter Component] Increment');
export const decrement = createAction('[Counter Component] Decrement');
export const reset = createAction('[Counter Component] Reset');
Create Reducer
import { createReducer, on } from '@ngrx/store';
import { increment, decrement, reset } from './counter.actions';
export const initialState = 0;
export const counterReducer = createReducer(
initialState,
on(increment, state => state + 1),
on(decrement, state => state - 1),
on(reset, state => 0)
);
Create Effect
import { Injectable } from '@angular/core';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { map } from 'rxjs/operators';
@Injectable()
export class CounterEffects {
loadMovies$ = createEffect(() => this.actions$.pipe(
ofType('[Counter Component] Increment'),
map(() => ({ type: '[Counter API] Increment Success' }))
));
constructor(private actions$: Actions) {}
}
Create Selector
import { createSelector } from '@ngrx/store';
export const selectFeature = state => state.feature;
export const selectFeatureCount = createSelector(
selectFeature,
(state: any) => state.count
);
NgRx Actions
Create Action with Payload
import { createAction, props } from '@ngrx/store';
export const addTodo = createAction(
'[Todo Component] Add Todo',
props<{ text: string }>()
);
Create Action with Multiple Payloads
import { createAction, props } from '@ngrx/store';
export const updateTodo = createAction(
'[Todo Component] Update Todo',
props<{ id: number, text: string }>()
);
Create Action with Optional Payload
import { createAction, props } from '@ngrx/store';
export const deleteTodo = createAction(
'[Todo Component] Delete Todo',
props<{ id: number }>()
);
NgRx Reducers
Create Reducer with Multiple Actions
import { createReducer, on } from '@ngrx/store';
import { addTodo, updateTodo, deleteTodo } from './todo.actions';
export const initialState = [];
export const todoReducer = createReducer(
initialState,
on(addTodo, (state, { text }) => [...state, { text }]),
on(updateTodo, (state, { id, text }) => state.map(todo => todo.id === id ? { ...todo, text } : todo),
on(deleteTodo, (state, { id }) => state.filter(todo => todo.id !== id))
);
Create Reducer with Entity Adapter
import { createEntityAdapter, EntityState } from '@ngrx/entity';
import { Todo } from './todo.model';
export interface TodoState extends EntityState<Todo> {}
export const todoAdapter = createEntityAdapter<Todo>();
export const initialState: TodoState = todoAdapter.getInitialState();
NgRx Effects
Create Effect with API Call
import { Injectable } from '@angular/core';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { map, mergeMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
import { TodoService } from './todo.service';
@Injectable()
export class TodoEffects {
loadTodos$ = createEffect(() => this.actions$.pipe(
ofType('[Todo Component] Load Todos'),
mergeMap(() => this.todoService.getTodos()
.pipe(
map(todos => ({ type: '[Todo API] Load Todos Success', todos })),
catchError(() => of({ type: '[Todo API] Load Todos Failure' }))
)
)
));
constructor(
private actions$: Actions,
private todoService: TodoService
) {}
}
Create Effect with Navigation
import { Injectable } from '@angular/core';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { tap } from 'rxjs/operators';
import { Router } from '@angular/router';
@Injectable()
export class RouterEffects {
navigate$ = createEffect(() => this.actions$.pipe(
ofType('[Router Component] Navigate'),
tap(() => this.router.navigate(['/home']))
));
constructor(
private actions$: Actions,
private router: Router
) {}
}
NgRx Selectors
Create Selector with Multiple Features
import { createSelector } from '@ngrx/store';
import { selectFeature1, selectFeature2 } from './feature.selectors';
export const selectFeature1Count = createSelector(
selectFeature1,
(state: any) => state.count
);
export const selectFeature2Count = createSelector(
selectFeature2,
(state: any) => state.count
);
Create Selector with Memoization
import { createSelector } from '@ngrx/store';
export const selectFeature = state => state.feature;
export const selectFeatureCount = createSelector(
selectFeature,
(state: any) => state.count
);
Create Selector with Props
import { createSelector } from '@ngrx/store';
export const selectFeature = state => state.feature;
export const selectFeatureById = createSelector(
selectFeature,
(state: any, props: { id: number }) => state.find(item => item.id === props.id)
);
NgRx Entity
Create Entity Adapter
import { createEntityAdapter, EntityState } from '@ngrx/entity';
import { Todo } from './todo.model';
export interface TodoState extends EntityState<Todo> {}
export const todoAdapter = createEntityAdapter<Todo>();
export const initialState: TodoState = todoAdapter.getInitialState();
Add Entity to Reducer
import { createReducer } from '@ngrx/store';
import { todoAdapter, initialState } from './todo.adapter';
export const todoReducer = createReducer(
initialState,
on(TodoActions.addTodo, (state, { todo }) => todoAdapter.addOne(todo, state)),
on(TodoActions.updateTodo, (state, { update }) => todoAdapter.updateOne(update, state)),
on(TodoActions.deleteTodo, (state, { id }) => todoAdapter.removeOne(id, state))
);
Select Entity from Store
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { todoAdapter, TodoState } from './todo.adapter';
export const selectTodoState = createFeatureSelector<TodoState>('todos');
export const {
selectIds,
selectEntities,
selectAll,
selectTotal,
} = todoAdapter.getSelectors(selectTodoState);
NgRx Router Store
Setup Router Store
import { StoreRouterConnectingModule } from '@ngrx/router-store';
@NgModule({
imports: [
StoreRouterConnectingModule.forRoot()
]
})
export class AppModule { }
Select Router State
import { RouterReducerState } from '@ngrx/router-store';
export const selectRouter = createFeatureSelector<RouterReducerState>('router');
Dispatch Router Action
import { Router } from '@angular/router';
import { go } from '@ngrx/router-store';
this.store.dispatch(go({ path: ['/home'] }));
NgRx Schematics
Generate NgRx Store
ng generate store State --root --statePath store --module app.module.ts
Generate NgRx Actions
ng generate action Counter --group --flat false
Generate NgRx Reducer
ng generate reducer counter --reducers index.ts
Generate NgRx Effect
ng generate effect counter --root --module app.module.ts
Generate NgRx Entity
ng generate entity todo --module app.module.ts
Generate NgRx Selector
ng generate selector counter --module app.module.ts
Generate NgRx Feature
ng generate feature counter --module app.module.ts
Generate NgRx Facade
ng generate facade counter --module app.module.ts
Generate NgRx Guard
ng generate guard auth --module app.module.ts
Generate NgRx Resolver
ng generate resolver user --module app.module.ts
Generate NgRx Component
ng generate component counter --module app.module.ts
Generate NgRx Service
ng generate service counter --module app.module.ts
Generate NgRx Pipe
ng generate pipe capitalize --module app.module.ts
Generate NgRx Directive
ng generate directive highlight --module app.module.ts
Generate NgRx Module
ng generate module counter --module app.module.ts
Generate NgRx Class
ng generate class user --module app.module.ts
Generate NgRx Interface
ng generate interface user --module app.module.ts
Generate NgRx Enum
ng generate enum status --module app.module.ts
Generate NgRx Typedef
ng generate typedef user --module app.module.ts
Conclusion
This NgRx cheatsheet covers all the essential concepts of NgRx. You can use this cheatsheet as a quick reference guide for NgRx development. If you have any questions or feedback, feel free to reach out to me. Happy coding! 🚀